<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html
  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Wine List</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <script type="text/javascript">
      //<![CDATA[
var WineListTransform;

(function () {

    function getDataCleanupText() {
      var t;
      t = '<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet version="1.0"';
      t = t + ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output';
      t = t + ' method="xml" encoding="utf-8" indent="yes" /> <xsl:template ma';
      t = t + 'tch="row"> <xsl:copy> <xsl:apply-templates select="@* | node()"';
      t = t + '/> <TypeGroup><xsl:apply-templates mode="type-group" select="."';
      t = t + ' /><\/TypeGroup> <TypeGroupSortOrder><xsl:apply-templates mode=';
      t = t + '"type-group-sort-order" select="." /><\/TypeGroupSortOrder> <Va';
      t = t + 'rietalGroup><xsl:apply-templates mode="varietal-group" select="';
      t = t + '." /><\/VarietalGroup> <TypeGroupVarietalSortOrder><xsl:apply-t';
      t = t + 'emplates mode="type-group-varietal-sort-order" select="." /><\/';
      t = t + 'TypeGroupVarietalSortOrder> <LocaleAbbreviated><xsl:apply-templ';
      t = t + 'ates mode="locale-abbreviated" select="." /><\/LocaleAbbreviate';
      t = t + 'd> <\/xsl:copy> <\/xsl:template> <xsl:template mode="type-group';
      t = t + '" match="row [ Type = \'White - Sparkling\' or Type = \'Rosé - ';
      t = t + 'Sparkling\' or Type = \'Red - Sparkling\' or Type = \'Rosé\' or';
      t = t + ' Type = \'White\' or Type = \'White - Off-dry\' ]" > <xsl:value';
      t = t + '-of select="\'Sparkling, Rosé, and White Wines\'"/> <\/xsl:temp';
      t = t + 'late> <xsl:template mode="type-group" match="row [ Type = \'Red';
      t = t + '\' ]" > <xsl:value-of select="\'Red Wines\'"/> <\/xsl:template>';
      t = t + ' <xsl:template mode="type-group" match="row [ Type = \'White - ';
      t = t + 'Sweet/Dessert\' or Type = \'Rosé - Sweet/Dessert\' or Type = \'';
      t = t + 'Red - Sweet/Dessert\' ]" > <xsl:value-of select="\'Dessert Wine';
      t = t + 's\'"/> <\/xsl:template> <xsl:template mode="type-group" match="';
      t = t + 'row [ Type = \'White - Fortified\' or Type = \'Red - Fortified';
      t = t + '\' or Type = \'Fruit/Vegetable Wine\' or Type = \'Sake\' or Typ';
      t = t + 'e = \'Spirits\' or Type = \'Liqueur\' or Type = \'Non-alcoholic';
      t = t + '\' ]" > <xsl:value-of select="\'Other\'"/> <\/xsl:template> <xs';
      t = t + 'l:template mode="type-group" match="row"> <xsl:value-of select=';
      t = t + '"Type"/> <\/xsl:template> <xsl:template mode="type-group-sort-o';
      t = t + 'rder" match="row"> <xsl:choose> <xsl:when test="Type = \'White ';
      t = t + '- Sparkling\'"><xsl:value-of select="1"/><\/xsl:when> <xsl:when';
      t = t + ' test="Type = \'Rosé - Sparkling\'"><xsl:value-of select="2"/><';
      t = t + '\/xsl:when> <xsl:when test="Type = \'Red - Sparkling\'"><xsl:va';
      t = t + 'lue-of select="3"/><\/xsl:when> <xsl:when test="Type = \'Rosé\'';
      t = t + '"><xsl:value-of select="4"/><\/xsl:when> <xsl:when test="Type =';
      t = t + ' \'White\'"><xsl:value-of select="5"/><\/xsl:when> <xsl:when te';
      t = t + 'st="Type = \'White - Off-dry\'"><xsl:value-of select="6"/><\/xs';
      t = t + 'l:when> <xsl:when test="Type = \'Red\'"><xsl:value-of select="7';
      t = t + '"/><\/xsl:when> <xsl:when test="Type = \'White - Sweet/Dessert';
      t = t + '\'"><xsl:value-of select="8"/><\/xsl:when> <xsl:when test="Type';
      t = t + ' = \'Rosé - Sweet/Dessert\'"><xsl:value-of select="9"/><\/xsl:w';
      t = t + 'hen> <xsl:when test="Type = \'Red - Sweet/Dessert\'"><xsl:value';
      t = t + '-of select="10"/><\/xsl:when> <xsl:when test="Type = \'White - ';
      t = t + 'Fortified\'"><xsl:value-of select="11"/><\/xsl:when> <xsl:when ';
      t = t + 'test="Type = \'Red - Fortified\'"><xsl:value-of select="12"/><';
      t = t + '\/xsl:when> <xsl:when test="Type = \'Fruit/Vegetable Wine\'"><x';
      t = t + 'sl:value-of select="13"/><\/xsl:when> <xsl:when test="Type = \'';
      t = t + 'Sake\'"><xsl:value-of select="14"/><\/xsl:when> <xsl:when test=';
      t = t + '"Type = \'Spirits\'"><xsl:value-of select="15"/><\/xsl:when> <x';
      t = t + 'sl:when test="Type = \'Liqueur\'"><xsl:value-of select="16"/><';
      t = t + '\/xsl:when> <xsl:when test="Type = \'Non-alcoholic\'"><xsl:valu';
      t = t + 'e-of select="17"/><\/xsl:when> <xsl:otherwise><xsl:value-of sel';
      t = t + 'ect="18"/><\/xsl:otherwise> <\/xsl:choose> <\/xsl:template> <xs';
      t = t + 'l:template mode="varietal-group" match="row [ Type = \'Rosé\' ]';
      t = t + '" > <xsl:apply-templates mode="varietal-group-suffix" select=".';
      t = t + '"> <xsl:with-param name="varietal-group-base" select="\'Rosé\'"';
      t = t + ' /> <\/xsl:apply-templates> <\/xsl:template> <xsl:template mode';
      t = t + '="varietal-group" match="row [ Type = \'White\' and ( MasterVar';
      t = t + 'ietal = \'White Rhone Blend\' or MasterVarietal = \'Pinot Gris-';
      t = t + 'Pinot Blanc Blend\' or MasterVarietal = \'Sémillon-Sauvignon Bl';
      t = t + 'anc Blend\' ) ]" > <xsl:apply-templates mode="varietal-group-su';
      t = t + 'ffix" select="."> <xsl:with-param name="varietal-group-base" se';
      t = t + 'lect="\'White Blend\'" /> <\/xsl:apply-templates> <\/xsl:templa';
      t = t + 'te> <xsl:template mode="varietal-group" match="row [ Type = \'R';
      t = t + 'ed\' and ( MasterVarietal = \'Cabernet-Syrah Blend\' ) ]" > <xs';
      t = t + 'l:apply-templates mode="varietal-group-suffix" select="."> <xsl';
      t = t + ':with-param name="varietal-group-base" select="\'Red Blend\'" /';
      t = t + '> <\/xsl:apply-templates> <\/xsl:template> <xsl:template mode="';
      t = t + 'varietal-group" match="row [ Type = \'Red\' and ( MasterVarieta';
      t = t + 'l = \'Red Bordeaux Blend\' ) ]" > <xsl:apply-templates mode="va';
      t = t + 'rietal-group-suffix" select="."> <xsl:with-param name="varietal';
      t = t + '-group-base" select="\'Red Blend - Bordeaux\'" /> <\/xsl:apply-';
      t = t + 'templates> <\/xsl:template> <xsl:template mode="varietal-group"';
      t = t + ' match="row [ Type = \'Red\' and ( MasterVarietal = \'SuperTusc';
      t = t + 'an Blend\' ) ]" > <xsl:apply-templates mode="varietal-group-suf';
      t = t + 'fix" select="."> <xsl:with-param name="varietal-group-base" sel';
      t = t + 'ect="\'Red Blend - SuperTuscan\'" /> <\/xsl:apply-templates> <';
      t = t + '\/xsl:template> <xsl:template mode="varietal-group" match="row"';
      t = t + '> <xsl:apply-templates mode="varietal-group-suffix" select=".">';
      t = t + ' <xsl:with-param name="varietal-group-base" select="MasterVarie';
      t = t + 'tal" /> <\/xsl:apply-templates> <\/xsl:template> <xsl:template ';
      t = t + 'mode="varietal-group-suffix" match="row [ Type = \'White - Spar';
      t = t + 'kling\' or Type = \'Rosé - Sparkling\' or Type = \'Red - Sparkl';
      t = t + 'ing\' ]" > <xsl:param name="varietal-group-base" /> <xsl:value-';
      t = t + 'of select="\'Sparkling\'" /> <\/xsl:template> <xsl:template mod';
      t = t + 'e="varietal-group-suffix" match="row"> <xsl:param name="varieta';
      t = t + 'l-group-base" /> <xsl:value-of select="$varietal-group-base" />';
      t = t + ' <\/xsl:template> <xsl:template mode="type-group-varietal-sort-';
      t = t + 'order" match="row"> <xsl:choose> <xsl:when test="Type = \'White';
      t = t + ' - Sparkling\'"><xsl:value-of select="1"/><\/xsl:when> <xsl:whe';
      t = t + 'n test="Type = \'Rosé - Sparkling\'"><xsl:value-of select="1"/>';
      t = t + '<\/xsl:when> <xsl:when test="Type = \'Red - Sparkling\'"><xsl:v';
      t = t + 'alue-of select="1"/><\/xsl:when> <xsl:when test="Type = \'Rosé';
      t = t + '\'"><xsl:value-of select="2"/><\/xsl:when> <xsl:when test="Type';
      t = t + ' = \'White\'"><xsl:value-of select="3"/><\/xsl:when> <xsl:when ';
      t = t + 'test="Type = \'White - Off-dry\'"><xsl:value-of select="3"/><\/';
      t = t + 'xsl:when> <xsl:when test="Type = \'Red\'"><xsl:value-of select=';
      t = t + '"4"/><\/xsl:when> <xsl:when test="Type = \'White - Sweet/Desser';
      t = t + 't\'"><xsl:value-of select="5"/><\/xsl:when> <xsl:when test="Typ';
      t = t + 'e = \'Rosé - Sweet/Dessert\'"><xsl:value-of select="5"/><\/xsl:';
      t = t + 'when> <xsl:when test="Type = \'Red - Sweet/Dessert\'"><xsl:valu';
      t = t + 'e-of select="6"/><\/xsl:when> <xsl:when test="Type = \'White - ';
      t = t + 'Fortified\'"><xsl:value-of select="7"/><\/xsl:when> <xsl:when t';
      t = t + 'est="Type = \'Red - Fortified\'"><xsl:value-of select="8"/><\/x';
      t = t + 'sl:when> <xsl:when test="Type = \'Fruit/Vegetable Wine\'"><xsl:';
      t = t + 'value-of select="9"/><\/xsl:when> <xsl:when test="Type = \'Sake';
      t = t + '\'"><xsl:value-of select="9"/><\/xsl:when> <xsl:when test="Type';
      t = t + ' = \'Spirits\'"><xsl:value-of select="9"/><\/xsl:when> <xsl:whe';
      t = t + 'n test="Type = \'Liqueur\'"><xsl:value-of select="9"/><\/xsl:wh';
      t = t + 'en> <xsl:when test="Type = \'Non-alcoholic\'"><xsl:value-of sel';
      t = t + 'ect="9"/><\/xsl:when> <xsl:otherwise><xsl:value-of select="10"/';
      t = t + '><\/xsl:otherwise> <\/xsl:choose> <\/xsl:template> <xsl:templat';
      t = t + 'e mode="locale-abbreviated" match="row [ Country = \'USA\' and ';
      t = t + 'Region = \'California\' and SubRegion = \'Unknown\' ]" > <xsl:v';
      t = t + 'alue-of select="\'California\'" /> <\/xsl:template> <xsl:templa';
      t = t + 'te mode="locale-abbreviated" match="row [ Country = \'USA\' and';
      t = t + ' Region = \'California\' and SubRegion != \'Unknown\' and not(b';
      t = t + 'oolean(Appellation/text())) ]" > <xsl:value-of select="SubRegio';
      t = t + 'n" /> <\/xsl:template> <xsl:template mode="locale-abbreviated" ';
      t = t + 'match="row [ Country = \'USA\' and Region = \'California\' and ';
      t = t + 'SubRegion != \'Unknown\' and boolean(Appellation/text()) ]" > <';
      t = t + 'xsl:value-of select="concat(SubRegion,\', \',Appellation)" /> <';
      t = t + '\/xsl:template> <xsl:template mode="locale-abbreviated" match="';
      t = t + 'row [ Country = \'USA\' and Region != \'California\' and boolea';
      t = t + 'n(Region/text()) ]" > <xsl:value-of select="substring(Locale,st';
      t = t + 'ring-length(\'USA, \') + 1)" /> <\/xsl:template> <xsl:template ';
      t = t + 'mode="locale-abbreviated" priority="1" match="row [ Locale = \'';
      t = t + 'USA, California, Central Coast, Santa Rita Hills - Sta. Rita Hi';
      t = t + 'lls\' ]" > <xsl:value-of select="\'Central Coast, Sta. Rita Hil';
      t = t + 'ls\'" /> <\/xsl:template> <xsl:template mode="locale-abbreviate';
      t = t + 'd" priority="1" match="row [ Country = \'France\' and Region = ';
      t = t + '\'Languedoc Roussillon\' and SubRegion = \'Languedoc\' and bool';
      t = t + 'ean(Appellation/text()) ]" > <xsl:value-of select="concat(\'Lan';
      t = t + 'guedoc, \', Appellation)" /> <\/xsl:template> <xsl:template mod';
      t = t + 'e="locale-abbreviated" priority="1" match="row [ Country = \'Fr';
      t = t + 'ance\' and Region = \'Languedoc Roussillon\' and SubRegion = \'';
      t = t + 'Roussillon\' and boolean(Appellation/text()) ]" > <xsl:value-of';
      t = t + ' select="concat(\'Roussillon, \', Appellation)" /> <\/xsl:templ';
      t = t + 'ate> <xsl:template mode="locale-abbreviated" priority="1" match';
      t = t + '="row [ Country = \'France\' and Region = \'Champagne\' and boo';
      t = t + 'lean(SubRegion/text()) and Appellation = \'Champagne\' ]" > <xs';
      t = t + 'l:value-of select="concat(Region, \', \', SubRegion)" /> <\/xsl';
      t = t + ':template> <xsl:template mode="locale-abbreviated" match="row [';
      t = t + ' Country = \'France\' and Region != \'France\' ]" > <xsl:value-';
      t = t + 'of select="substring(Locale,string-length(\'France, \') + 1)" /';
      t = t + '> <\/xsl:template> <xsl:template mode="locale-abbreviated" matc';
      t = t + 'h="row [ Country = \'Italy\' and boolean(SubRegion/text()) and ';
      t = t + 'boolean(Appellation/text()) and concat(SubRegion, \' DOC\') = A';
      t = t + 'ppellation ]" > <xsl:value-of select="concat(Country, \', \', R';
      t = t + 'egion, \', \', Appellation)" /> <\/xsl:template> <xsl:template ';
      t = t + 'mode="locale-abbreviated" match="row [ Locale = \'Italy, Piedmo';
      t = t + 'nt, Monferrato, Barbera del Monferrato\' ]" > <xsl:value-of sel';
      t = t + 'ect="\'Italy, Piedmont, Barbera del Monferrato\'" /> <\/xsl:tem';
      t = t + 'plate> <xsl:template mode="locale-abbreviated" match="row [ Cou';
      t = t + 'ntry = \'Australia\' and Region = \'South Australia\' ]" > <xsl';
      t = t + ':value-of select="substring(Locale,string-length(\'Australia, ';
      t = t + '\') + 1)" /> <\/xsl:template> <xsl:template mode="locale-abbrev';
      t = t + 'iated" match="row"> <xsl:value-of select="Locale" /> <\/xsl:tem';
      t = t + 'plate> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply';
      t = t + '-templates select="@* | node()"/> <\/xsl:copy> <\/xsl:template>';
      t = t + '<\/xsl:stylesheet>';
      return t;
    }

    function getDataPresentationText() {
      var t;
      t = '<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet version="1.0"';
      t = t + ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="';
      t = t + 'urn:schemas-microsoft-com:xslt" xmlns="http://www.w3.org/1999/x';
      t = t + 'html" exclude-result-prefixes="msxsl" > <xsl:output method="htm';
      t = t + 'l" indent="yes" encoding="utf-8" omit-xml-declaration="no" doct';
      t = t + 'ype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="h';
      t = t + 'ttp://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" /> <xsl:varia';
      t = t + 'ble name="wines-in-stock" select="/cellartracker/list/row[Quant';
      t = t + 'ity > 0 and Location != \'Wine Fridge - Tasting group\']" /> <x';
      t = t + 'sl:key name="wines-by-type-group" match="/cellartracker/list/ro';
      t = t + 'w[Quantity > 0 and Location != \'Wine Fridge - Tasting group\']';
      t = t + '" use="TypeGroup" /> <xsl:key name="wines-by-varietal-group" ma';
      t = t + 'tch="/cellartracker/list/row[Quantity > 0 and Location != \'Win';
      t = t + 'e Fridge - Tasting group\']" use="VarietalGroup" /> <xsl:key na';
      t = t + 'me="wines-by-id" match="/cellartracker/list/row[Quantity > 0 an';
      t = t + 'd Location != \'Wine Fridge - Tasting group\']" use="iWine" /> ';
      t = t + '<xsl:template match="/cellartracker"> <div class="wine-list"> <';
      t = t + 'xsl:for-each select="$wines-in-stock[count(. | key(\'wines-by-t';
      t = t + 'ype-group\', TypeGroup)[1]) = 1]"> <xsl:sort select="TypeGroupS';
      t = t + 'ortOrder" data-type="number" /> <xsl:variable name="current-typ';
      t = t + 'e-group" select="TypeGroup" /> <div class="type-group"> <xsl:fo';
      t = t + 'r-each select="$wines-in-stock[TypeGroup = $current-type-group ';
      t = t + 'and count(. | key(\'wines-by-varietal-group\', VarietalGroup)[1';
      t = t + ']) = 1]"> <xsl:sort select="TypeGroupVarietalSortOrder" data-ty';
      t = t + 'pe="number" /> <xsl:sort select="VarietalGroup" /> <xsl:variabl';
      t = t + 'e name="current-varietal-group" select="VarietalGroup" /> <xsl:';
      t = t + 'variable name="current-varietal-group-position" select="positio';
      t = t + 'n()" /> <xsl:for-each select="$wines-in-stock[TypeGroup = $curr';
      t = t + 'ent-type-group and VarietalGroup = $current-varietal-group and ';
      t = t + 'count(. | key(\'wines-by-id\', iWine)[1]) = 1]"> <xsl:sort sele';
      t = t + 'ct="SortProducer" /> <xsl:sort select="Wine" /> <xsl:choose> <x';
      t = t + 'sl:when test="$current-varietal-group-position = 1 and position';
      t = t + '() = 1"> <table class="avoid-break"> <tbody> <tr> <td> <div cla';
      t = t + 'ss="type-heading"> <xsl:value-of select="TypeGroup" /> <\/div> ';
      t = t + ' <div class="varietal-heading"> <xsl:value-of select="$current-';
      t = t + 'varietal-group" /> <\/div> <xsl:apply-templates select="."/> <';
      t = t + '\/td> <\/tr> <\/tbody> <\/table> <\/xsl:when> <xsl:when test="p';
      t = t + 'osition() = 1"> <table class="avoid-break"> <tbody> <tr> <td> <';
      t = t + 'div class="varietal-heading"> <xsl:value-of select="$current-va';
      t = t + 'rietal-group" /> <\/div> <xsl:apply-templates select="."/> <\/t';
      t = t + 'd> <\/tr> <\/tbody> <\/table> <\/xsl:when> <xsl:otherwise> <tab';
      t = t + 'le class="avoid-break"> <tbody> <tr> <td> <xsl:apply-templates ';
      t = t + 'select="."/> <\/td> <\/tr> <\/tbody> <\/table> <\/xsl:otherwise';
      t = t + '> <\/xsl:choose> <\/xsl:for-each> <\/xsl:for-each> <\/div> <\/x';
      t = t + 'sl:for-each> <div class="legend"> <div>&#x25CA; Could benefit f';
      t = t + 'rom further cellaring<\/div> <div>&#x2302; House quality wine<';
      t = t + '\/div> <\/div> <\/div> <\/xsl:template> <xsl:template match="ro';
      t = t + 'w"> <div class="wine"> <span class="wine-name-and-locale"> <xsl';
      t = t + ':choose> <xsl:when test="Location = \'Wine Fridge - Future\'"> ';
      t = t + '<span class="wine-status-indicator wine-status-future"> <xsl:te';
      t = t + 'xt>&#x25CA;<\/xsl:text> <\/span> <xsl:text> <\/xsl:text> <\/xsl';
      t = t + ':when> <xsl:when test="Location = \'Wine Fridge - House\'"> <sp';
      t = t + 'an class="wine-status-indicator wine-status-house"> <xsl:text>&';
      t = t + '#x2302;<\/xsl:text> <\/span> <xsl:text> <\/xsl:text> <\/xsl:whe';
      t = t + 'n> <\/xsl:choose> <xsl:if test="Vintage != \'1001\'"> <span cla';
      t = t + 'ss="vintage"> <xsl:value-of select="Vintage"/> <\/span> <xsl:te';
      t = t + 'xt> <\/xsl:text> <\/xsl:if> <span class="wine-name"> <xsl:value';
      t = t + '-of select="Wine" /> <\/span> <xsl:text> <\/xsl:text> <span cla';
      t = t + 'ss="locale"> <xsl:text>(<\/xsl:text> <xsl:call-template name="o';
      t = t + 'utput-locale"> <xsl:with-param name="value" select="LocaleAbbre';
      t = t + 'viated" /> <\/xsl:call-template> <xsl:text>)<\/xsl:text> <\/spa';
      t = t + 'n> <\/span> <span class="bin-and-price-list"> <xsl:for-each sel';
      t = t + 'ect="key(\'wines-by-id\', iWine)"> <xsl:sort select="Bin" data-';
      t = t + 'type="number" /> <span class="bin"> <xsl:value-of select="Bin" ';
      t = t + '/> <\/span> <xsl:if test="not(position() = last())"> <xsl:text>';
      t = t + ', <\/xsl:text> <\/xsl:if> <xsl:if test="position() = last() and';
      t = t + ' number(Price) > 0"> <span class="price-list-item"> <xsl:text>,';
      t = t + ' <\/xsl:text> <\/span> <\/xsl:if> <\/xsl:for-each> <xsl:if test';
      t = t + '="number(Price) > 0"> <span class="price price-list-item"> <xsl';
      t = t + ':text>$<\/xsl:text> <xsl:value-of select="ceiling(number(Price)';
      t = t + ')" /> <\/span> <\/xsl:if> <\/span> <\/div> <\/xsl:template> <xs';
      t = t + 'l:template name="output-locale"> <xsl:param name="value" /> <xs';
      t = t + 'l:variable name="first" select="substring-before($value, \', \'';
      t = t + ')" /> <xsl:variable name="remaining" select="substring-after($v';
      t = t + 'alue, \', \')" /> <xsl:choose> <xsl:when test="$value and not($';
      t = t + 'first)"> <xsl:call-template name="output-locale-section"> <xsl:';
      t = t + 'with-param name="value" select="$value" /> <\/xsl:call-template';
      t = t + '> <\/xsl:when> <xsl:when test="$first"> <xsl:call-template name';
      t = t + '="output-locale-section"> <xsl:with-param name="value" select="';
      t = t + '$first" /> <\/xsl:call-template> <xsl:text>, <\/xsl:text> <\/xs';
      t = t + 'l:when> <\/xsl:choose> <xsl:if test="$remaining"> <xsl:call-tem';
      t = t + 'plate name="output-locale"> <xsl:with-param name="value" select';
      t = t + '="$remaining" /> <\/xsl:call-template> <\/xsl:if> <\/xsl:templa';
      t = t + 'te> <xsl:template name="output-locale-section"> <xsl:param name';
      t = t + '="value" /> <xsl:variable name="first" select="substring-before';
      t = t + '($value, \' \')" /> <xsl:variable name="remaining" select="subs';
      t = t + 'tring-after($value, \' \')" /> <xsl:choose> <xsl:when test="$va';
      t = t + 'lue and not($first)"> <xsl:value-of select="$value" /> <\/xsl:w';
      t = t + 'hen> <xsl:when test="$first"> <xsl:value-of select="$first" /> ';
      t = t + '<xsl:text disable-output-escaping="yes">&#160;<\/xsl:text> <\/x';
      t = t + 'sl:when> <\/xsl:choose> <xsl:if test="$remaining"> <xsl:call-te';
      t = t + 'mplate name="output-locale-section"> <xsl:with-param name="valu';
      t = t + 'e" select="$remaining" /> <\/xsl:call-template> <\/xsl:if> <\/x';
      t = t + 'sl:template> <\/xsl:stylesheet>';
      return t;
    }

    var ellipsis,
      queryString,
      dataCleanupProcessor,
      dataPresentationProcessor,
      progressAnimation,
      rawDataURL,
      rawDataXML;
    
    ellipsis = String.fromCharCode(8230);

    function el(id) {
      return document.getElementById(id);
    }

    function getSingleElementByClassName(el, names) {
      var list;
      
      list = el.getElementsByClassName(names);
      if (list.length === 1) {
        return list[0];
      }
    }

    function setElementText(id, text) {      
      var element;

      element = el(id);
      
      while (element.firstChild !== null) {
        element.removeChild(element.firstChild);
      }
      element.appendChild(document.createTextNode(text));
    }
    
    function findClass(elementClass, className) {
      var currentClasses,
        existingClassIndex,
        i,
        length;

      currentClasses = elementClass.split(/\s+/);
      length = currentClasses.length;
      for (i = 0; i < length; i++) {
        if (currentClasses[i].toLowerCase() === className.toLowerCase()) {
          existingClassIndex = i;
          break;
        }
      }
      
      return {
        currentClasses: currentClasses,
        existingClassIndex: existingClassIndex
      };
    }
    
    function addClass(id, className) {
      var classFindResult,
        element;

      element = el(id);
      classFindResult = findClass(element.className, className);
      
      if (typeof classFindResult.existingClassIndex === 'undefined') {
        element.className += ' ' + className;
      }
    }
    
    function removeClass(id, className) {
      var classFindResult,
        element;

      element = el(id);
      classFindResult = findClass(element.className, className);
      
      if (typeof classFindResult.existingClassIndex !== 'undefined') {
        classFindResult.currentClasses.splice(classFindResult.existingClassIndex, 1);
        element.className = classFindResult.currentClasses.join(' ');
      }
    }
    
    function setProgressStatus(text) {
      setElementText('progress-status', text);
    }

    function setBlockElementVisible(id, visible) {
      var element;

      element = el(id);

      if (visible) {
        element.style.display = "block";
      } else {
        element.style.display = "none";
      }
    }
    
    function setMainContentVisible(visible) {
      setBlockElementVisible('main', visible);
    }

    function setProgressVisible(visible) {
      setBlockElementVisible('progress', visible);
    }

    function setWineListVisible(visible) {
      setBlockElementVisible('wine-list-wrapper', visible);
    }

    function setSpinnerCompleted(completed) {
      var operation;
      
      if (completed) {
        operation = addClass;
      } else {
        operation = removeClass;
      }
      
      operation.call(this, 'spinner', 'completed');
    }

    function showMainContent() {
      setMainContentVisible(true);
      setProgressVisible(false);
      setWineListVisible(false);
    }
    
    function showProgress() {
      setSpinnerCompleted(false);
    
      setMainContentVisible(false);
      setProgressVisible(true);
      setWineListVisible(false);
    }

    function showWineList() {
      setMainContentVisible(false);
      setProgressVisible(false);
      setWineListVisible(true);
    }

    function getXMLAsyncXHR(url, callback) {
      var req;

      req = new XMLHttpRequest();
      req.onreadystatechange = function() {
        if (req.readyState == 4) {
          if (!(req.status == 200 || req.status == 0)) {
            callback.call(this, null);
          } else {
            callback.call(this, req.responseXML);
          }
        }
      };
      req.open('GET', url, true);
      req.send(null);
    }
    
    function getRawQueryString() {
      var result,
          queryString,
          re,
          m;

      result = {};
      queryString = location.search.substring(1);
      re = /([^&=]+)=([^&]*)/g;

      while (m = re.exec(queryString)) {
        result[decodeURIComponent(m[1]).toLowerCase()] = m[2];
      }

      return result;
    }

    function getIsTwoColumnLayoutFromQueryString() {
      return queryString["columns"] == 2;
    }

    function getHidePricesFromQueryString() {
      var hidePricesParam;
      
      hidePricesParam = queryString['hideprices'];
      
      if (typeof hidePricesParam !== "undefined") {
        if (hidePricesParam.toLowerCase() === 'true' || hidePricesParam === '1') {
          return true;
        }
      }
      
      return false;
    }

    function getCredentialsFromQueryString() {
      return {
        user: queryString["user"],
        password: queryString["password"]
      };
    }

    function getCredentialsFromForm() {
      return {
        user: el('user-input').value,
        password: el('password-input').value
      };
    }
    
    function computeNeededWineListWidth(parentEl, classNames, percent) {
      var el;
      
      el = getSingleElementByClassName(parentEl, classNames);
      
      if (el && el.scrollWidth > el.offsetWidth) {
        // 4px for table spacing
        return Math.ceil(el.scrollWidth / percent) + 4;
      } else {
        return 0;
      }
    }
        
    function updateLayout() {
      var columnCount,
        i,
        length,
        wineMaxWidth,
        wineListEl,
        wineListWrapperEl,
        wineListMinWidth,
        wineNodes;
        
      wineListWrapperEl = el('wine-list-wrapper');
      if (wineListWrapperEl) {
        wineListEl = getSingleElementByClassName(wineListWrapperEl, 'wine-list');
      }
      
      if (wineListEl) {
        wineNodes = wineListEl.getElementsByClassName('wine');
        length = wineNodes.length;
        wineMaxWidth = 0;
        
        for (i = 0; i < length; i++) {
          // 78% width from CSS
          wineMaxWidth = Math.max(wineMaxWidth, computeNeededWineListWidth(wineNodes[i], 'wine-name-and-locale', 0.78));

          // 20% width plus 2% padding from CSS
          wineMaxWidth = Math.max(wineMaxWidth, computeNeededWineListWidth(wineNodes[i], 'bin-and-price-list', 0.22));
          
          // If the chlid elements don't take up the full width, it doesn't matter.
          //// The child elements may not take up the full width due to CSS rounding
          //wineMaxWidth = Math.max(wineMaxWidth, wineNodes[i].offsetWidth + 4);
        }
        
        columnCount = (getIsTwoColumnLayoutFromQueryString() ? 2 : 3);

        //Set .wine-list min-width =
        //  (maximum width of .wine) * (column count of 3)
        //  + (column gap of 20) * ((column count of 3) - 1)
        wineListMinWidth = (wineMaxWidth * columnCount) + (20 * (columnCount - 1));        
        
        wineListMinWidth = Math.round(wineListMinWidth); //Make sure we didn't end up with a floating point number
        
        //HACK: I'm not sure why, but in Firefox the computed wineListMinWidth seems to always
        // be 3px bigger than the offsetWidth. This could be related to the 4px of table spacing.
        // Whithout this correction, resizing the page larger makes the minWidth grow.
        // In Chrome the wine locale is cut off by about one pixel, which may be related to this adjustment.
        wineListMinWidth -= 3;
        
        if (wineListEl.offsetWidth < wineListMinWidth) {
          //console.log('Updating wineListEl.style.minWidth. wineListEl.offsetWidth: ' + wineListEl.offsetWidth + ' wineListMinWidth: ' + wineListMinWidth);
          wineListEl.style.minWidth = wineListMinWidth + 'px';
        }
      }
      
    }

    function init() {
      var dataCleanupXML,
        dataPresentationXML,
        parser;

      queryString = getRawQueryString();
      
      if (getHidePricesFromQueryString()) {
        addClass('wine-list-wrapper', 'hide-prices');
      }

      if (getIsTwoColumnLayoutFromQueryString()) {
        addClass('wine-list-wrapper', 'two-column');
      }
      
      parser = new DOMParser();

      dataCleanupXML = parser.parseFromString(getDataCleanupText(), "text/xml");
      dataCleanupProcessor = new XSLTProcessor();
      dataCleanupProcessor.importStylesheet(dataCleanupXML);

      dataPresentationXML = parser.parseFromString(getDataPresentationText(), "text/xml");
      dataPresentationProcessor = new XSLTProcessor();
      dataPresentationProcessor.importStylesheet(dataPresentationXML);
      
      window.onresize = (function () {
        var resizeTimeoutId;
        
        return function () {
          window.clearTimeout(resizeTimeoutId);
          resizeTimeoutId = window.setTimeout(updateLayout, 10);
        };
      })();
    }

    function processRawData() {
      var cleanDataXML,
          presentationHTML;
          
      cleanDataXML = dataCleanupProcessor.transformToDocument(rawDataXML);
      presentationHTML = dataPresentationProcessor.transformToFragment(cleanDataXML, document);
      el('wine-list-wrapper').appendChild(presentationHTML);
    }

    function getResponseErrorMessage(response) {
      var root,
          body;

      root = rawDataXML.documentElement;

      //An HTML response from CellarTracker indicates an error, stored in the body element.
      if (root && root.localName == "html" && root.namespaceURI === null) {
        body = root.firstChild;
        if (body && body.localName == "body" && body.namespaceURI === null) {
          return body.textContent;
        }
      }

      return;
    }

    function isLoginErrorResponse(response) {
      var responseErrorMessage;

      responseErrorMessage = getResponseErrorMessage(rawDataXML);
      if (responseErrorMessage == "You are currently not logged into CellarTracker.") {
        return true;
      }

      return false;
    }

    function loadRawDataUsingXHR(credentials, callback) {
      rawDataURL = "http://www.cellartracker.com/xlquery.asp?table=List&Location=1&User=" + credentials.user + "&Password=" + credentials.password + "&Format=xml";
      getXMLAsyncXHR(rawDataURL, function (response) {
        rawDataXML = response;
        
        if (isLoginErrorResponse(rawDataXML)) {
          alert("There was an error logging in. Please visit CellarTracker to confirm that your handle and password are correct.");
          callback.call(this, credentials, false);
        } else {
          callback.call(this, credentials, true);
        }
      });
    }
    
    function updatePageUri(newUri) {
      window.onpopstate = function () {
        queryString = getRawQueryString();
        loadWineListWithQueryStringCredentials();
      };

      window.history.pushState(null, 'Wine List', newUri);
      queryString = getRawQueryString();
    }

    function updatePageState(credentials, succeeded) {
      var queryCredentials,
          newUri;

      queryCredentials = getCredentialsFromQueryString();

      progressAnimation.stop();
      
      if (succeeded) {
        setSpinnerCompleted(true);
        setProgressStatus('Formatting data');
        
        setTimeout(function () {
          processRawData();
          showWineList();
          updateLayout();
          
          if (queryCredentials.user !== credentials.user || queryCredentials.password !== credentials.password) {
            updatePageUri("?User=" + encodeURIComponent(credentials.user) + "&Password=" + encodeURIComponent(credentials.password));
          }
          
        }, 200);

      } else {
        showMainContent();

        if (queryCredentials.user || queryCredentials.password) {
          updatePageUri('?');
        }
      }
    }

    function loadWineList(credentials) {
      var succeeded;

      if (credentials.user && credentials.password) {
        setProgressStatus('Downloading data' + ellipsis);
        showProgress();
        progressAnimation.start();
        
        loadRawDataUsingXHR(credentials, updatePageState);
        
      } else {
        updatePageState(credentials, succeeded);
      }
    }

    function loadWineListWithQueryStringCredentials() {
      var credentials;

      credentials = getCredentialsFromQueryString();
      loadWineList(credentials);
    }

    function loadWineListWithFormCredentials() {
      var credentials;

      credentials = getCredentialsFromForm();

      if (credentials.user && credentials.password) {
        loadWineList(credentials);

      } else {
        alert("A CellarTracker handle and password are required.");
        updatePageState(credentials, false);
      }
    }

  progressAnimation = (function() {
    var count,
      delay,
      timeoutId;
    
    delay = 100;
    count = 0;
    
    function rotate() {
      var spinnerEl,
        transform;
        
      spinnerEl = document.getElementById('spinner');
      transform = 'scale(0.5) rotate(' + count + 'deg)';
      spinnerEl.style.MozTransform = transform;
      spinnerEl.style.WebkitTransform = transform;

      if (count === 360) {
        count = 0;
      }
      count += 45;
      
      timeoutId = window.setTimeout(rotate, delay);
    }
    
    function stopCore() {
        if (typeof timeoutId !== 'undefined') {
          window.clearTimeout(timeoutId);
          timeoutId = undefined;
        }
    }
    
    return {
      start: function() {
        stopCore();
        timeoutId = window.setTimeout(rotate, delay);
      },
      
      stop: function() {
        stopCore();
      }
    };

  })();

  WineListTransform = {

    loadWineList: function () {
      init();
      loadWineListWithQueryStringCredentials();
    },

    handleCredentialsFormSubmit: function (e) {
      e.preventDefault();
      loadWineListWithFormCredentials();
    }

  };

})();
    //]]>
    </script>

    <style type="text/css">
    
    #progress {
      display: none;
      position: relative;
      max-width: 17em;
      margin: 0 auto;
      border: 1px solid black;
    }
    #progress-status {
      left: 100px;
      height: 100px;
      display: table-cell;
      vertical-align: middle;
    }
    
    /* Progress spinner. See http://kilianvalkhof.com/2010/css-xhtml/css3-loading-spinners-without-images/ */
    /* position the bars and balls correctly (rotate them and translate them outward)*/
    #spinner {
      position:relative;
      width:100px;
      height:100px;
      float:left;
      -moz-border-radius:100px;
      -webkit-border-radius:100px;
      -moz-transform:scale(0.5);
      -webkit-transform:scale(0.5);
    }
    #spinner div {
      width:20px;
      height:20px;
      background:#000;
      -moz-border-radius:40px;
      -webkit-border-radius:40px;
      position:absolute;
      left:40px;
      top:40px;
      -moz-box-shadow:black 0 0 4px;
      -webkit-box-shadow:black 0 0 4px;
    }
    #spinner.completed div {
      opacity: 1;
    }
    .bar1 {
      -moz-transform:rotate(0deg) translate(0, -40px);
      -webkit-transform:rotate(0deg) translate(0, -40px);
      opacity:0.12;
    }
    .bar2 {
      -moz-transform:rotate(45deg) translate(0, -40px);
      -webkit-transform:rotate(45deg) translate(0, -40px);
      opacity:0.25;
    }
    .bar3 {
      -moz-transform:rotate(90deg) translate(0, -40px);
      -webkit-transform:rotate(90deg) translate(0, -40px);
      opacity:0.37;
    }
    .bar4 {
      -moz-transform:rotate(135deg) translate(0, -40px);
      -webkit-transform:rotate(135deg) translate(0, -40px);
      opacity:0.50;
    }
    .bar5 {
      -moz-transform:rotate(180deg) translate(0, -40px);
      -webkit-transform:rotate(180deg) translate(0, -40px);
      opacity:0.62;
    }
    .bar6 {
      -moz-transform:rotate(225deg) translate(0, -40px);
      -webkit-transform:rotate(225deg) translate(0, -40px);
      opacity:0.75;
    }
    .bar7 {
      -moz-transform:rotate(270deg) translate(0, -40px);
      -webkit-transform:rotate(270deg) translate(0, -40px);
      opacity:0.87;
    }
    .bar8 {
      -moz-transform:rotate(315deg) translate(0, -40px);
      -webkit-transform:rotate(315deg) translate(0, -40px);
      opacity:1;
    }
    
    #main {
      margin-left: auto;
      margin-right: auto;
      width: 40%;
      min-width: 35em;
      display: none;
    }

    #credentials-prompt {
      text-align: center;
      margin: 0.5em;
    }

    #credentials-prompt > span {
      display: inline-block;
      border: 1px solid black;
      text-align: left;
    }

    #credentials-fields {
      padding: 0.2em 0.5em 0.2em 0.5em;
    }

    #footer {
      text-align: center;
    }
    </style>

    <style type="text/css">
    body {
      font-size: 100%;
      min-width: 550px;
    }

    .wine-list {
      -webkit-column-count: 3;
      -webkit-column-gap: 20px;
      /*
      -webkit-column-width: 20em;
      -webkit-column-gap: 2em;
      */
      -webkit-column-rule-color: black;
      -webkit-column-rule-style: solid;
      -webkit-column-rule-width: 2px;
      -moz-column-count: 3;
      -moz-column-gap: 20px;
      /*
      -moz-column-width: 20em;
      -moz-column-gap: 2em;
      */
      -moz-column-rule-color: black;
      -moz-column-rule-style: solid;
      -moz-column-rule-width: 2px;
      column-count: 3;
      column-gap: 20px;
      /*
      -column-width: 20em;
      -column-gap: 2em;
      */
      column-rule-color: black;
      column-rule-style: solid;
      column-rule-width: 2px;
    }

    .type-group {
    }

    #wine-list-wrapper.two-column>.wine-list {
      -webkit-column-count: 2;
      -moz-column-count: 2;
      column-count: 2;
    }

    .type-heading {
      clear: both;
      font-size: 2em;
      font-weight: bold;
      font-family: Arial,Helvetica,sans-serif;
      font-variant: small-caps;
      text-align: center;
      background: #F3F3F3;
      border-top: solid windowtext .5pt;
      border-bottom: solid windowtext .5pt;
      margin-bottom: 0.3em;
    }

    .varietal-group {
    }

    .varietal-heading {
      clear:both;
      margin-top: 0.6em;
      font-weight: bold;
    }

    .wine {
      clear: both;
      -webkit-column-break-inside: avoid;
      -moz-column-break-inside: avoid;
      column-break-inside: avoid;
    }

    table.avoid-break {
      width: 100%;
      -webkit-column-break-inside: avoid;
      -moz-column-break-inside: avoid;
      column-break-inside: avoid;
    }

    table.avoid-break td {
      padding: 0;
    }

    .wine-name-and-locale {
      display: block; /* Display must be block or inline-block so the width rules are respected. */
      overflow: hidden;
      width: 78%;
      float: left;
      margin-bottom: 0.2em;
    }

    .wine-name {
    }

    .locale {
      font-style: italic;
      font-size: 0.8em;
      /* white-space: nowrap; */
    }

    .bin-and-price-list {
      text-align: right;
      padding-left: 2%;
      display: block; /* Display must be block or inline-block so the width rules are respected. */
      overflow: hidden;
      width: 20%; /* Use the same width so we don't have to recompute the width available for the wine name on each row. */
      float: right;
      margin-bottom: 0.2em;
    }

    .hide-prices .price-list-item {
      display: none;
    }

    .price {
      font-style: italic;
    }

    .legend {
      padding-top: 0.5em;
      /* -webkit-column-break-inside: avoid; */
      /* break-inside: avoid-column; */
    }
  </style>
  </head>
  <body onload="WineListTransform.loadWineList();">
    <div id="main">
      <h1>Cellar View</h1>
      <p>Extend the viewing options available from CellarTracker. Provide your CellarTracker!&trade; information below, then load the wine list. Bookmark the wine list page to get back to it without reentering your user information.</p>
      <p>Note that your password will be sent to CellarTracker in plain text and will be visible in your browser's address bar.</p>
      <div id="credentials-prompt">
        <span>
          <form id="credentials-form" onSubmit="WineListTransform.handleCredentialsFormSubmit(event);">
            <table id="credentials-fields">
              <tr>
                <th colspan="2">CellarTracker!&trade; user information</th>
              </tr>
              <tr>
                <td>Handle:</td>
                <td><input id="user-input" type="text" /></td>
              </tr>
              <tr>
                <td>Password:</td>
                <td><input id="password-input" type="password" /></td>
              </tr>
              <tr>
                <td colspan="2" align="right">
                  <input type="submit" value="Load wine list" />
                </td>
              </tr>
            </table>
          </form>
        </span>
      </div>
      <div id="footer">
        <span><a href="http://code.google.com/p/cellar-view/" title="Cellar View on Google Code">About Cellar View</a> - <a href="http://www.cellartracker.com/">CellarTracker!&trade;</a>
      </div>
    </div>
    <div id="progress">
      <div id="spinner">
        <div class="bar1"></div>
        <div class="bar2"></div>
        <div class="bar3"></div>
        <div class="bar4"></div>
        <div class="bar5"></div>
        <div class="bar6"></div>
        <div class="bar7"></div>
        <div class="bar8"></div>
      </div>
      <div id="progress-status"></div>
    </div>
    <div id="wine-list-wrapper"></div>
  </body>
</html>
